/******************************************************************************
 cnome: A C++ source "genes" discover. :-)

 See more details at:

   http://www.codeplex.com/cnome

 The original author site is at: http://www.alexandre-barbosa.com/

 Copyright (c) 2008 Alexandre Barbosa.
 Distributed under the MIT License. (See accompanying file LICENSE-MIT.txt 
 or at http://www.codeplex.com/cnome/license)
 ******************************************************************************/

#if defined(_MSC_VER) && (_MSC_VER >= 1400)
#pragma warning ( disable : 4996 )
#pragma warning ( disable : 4800 )
#pragma warning ( disable : 4355 )
#endif

#include <exception>

#include <boost/wave/cpplexer/cpp_lex_token.hpp>

#include "symbol_item.h"

using namespace boost::wave;
using namespace std;

namespace cnome {
cnome_symbolsT cnome_symbols;

const char* symbolItem::strSymbolType[last_symbolType] = {
        "unknown",
        "internal",
        "keyword",  // char, int, long, float, double, boolean
        "member",
        "method",
        "enumerator",
        "enun_name",
        "parameter",
        "typedefname",
        "pointer to function",
		"template_variable",
        "other" };

const char* symbolItem::strStatusDD[last_statusDD] = {
        "unknow",
        "declared",
        "defined" };

symbolItem::symbolItem():  m_typeTk(symbolItemPtr(static_cast<symbolItem*>(0))), m_sblTyp(unknown), m_scope(symbolItemPtr(static_cast<symbolItem*>(0))),
        m_stt(declared), m_str(0), m_inners(), m_inrsCreated(),
        m_paramPos(-1), m_identifierType(NONE), m_pos(0) {
    update_str();
}
    
symbolItem::symbolItem(token_id argTkId, std::size_t a_pos): m_typeTk(symbolItemPtr(static_cast<symbolItem*>(0))), m_sblTyp(unknown),
        m_scope(symbolItemPtr(static_cast<symbolItem*>(0))), m_stt(declared), m_str(0), m_inners(), m_inrsCreated(),
        m_paramPos(-1), m_identifierType(NONE), m_pos(a_pos) {
    set_token_id(argTkId);
    update_str();
}

symbolItem::symbolItem(const token_t& argTk, symbolType s, std::size_t a_pos): token_t(argTk), m_typeTk(symbolItemPtr(static_cast<symbolItem*>(0))),
        m_sblTyp(s),m_scope(symbolItemPtr(static_cast<symbolItem*>(0))),m_stt(declared), m_str(0), m_inners(), m_inrsCreated(),
        m_paramPos(-1), m_identifierType(NONE), m_pos(a_pos) {
	//m_definitions.push_back(argTk);
    update_str();
}

symbolItem::symbolItem(const symbolItem& s):  token_t(s), m_definitions(s.m_definitions), m_declarations(s.m_declarations),
        m_references(s.m_references), m_typeTk(s.m_typeTk),
        m_sblTyp(s.m_sblTyp),m_scope(s.m_scope),m_stt(s.m_stt), m_str(0), m_adorners(s.m_adorners), 
        m_inners(s.m_inners), m_inrsCreated(s.m_inrsCreated), m_paramPos(s.m_paramPos), m_identifierType(s.m_identifierType), 
		m_pos(s.m_pos) {
    if (s.m_scope.get() == this)
       throw exception();
       //throw exception("Internal error");

    update_str();
}

symbolItem::~symbolItem() {
    delete[] m_str;
}

void  symbolItem::set_type_symbol(const symbolItemPtr s) {m_typeTk=s; }

void  symbolItem::set_scope(const symbolItemPtr s) {
    if (s.get() == this)
      // throw exception("Internal error");
       throw exception();
    m_scope = s;
    update_str();
}

void symbolItem::update_str() {
    const unsigned int MAXSCOPE = 10000;
    std::string scp;

    if (*this != T_IDENTIFIER && *this != T_OPERATOR)
        scp = get_value().c_str();
    else {
        std::list<const symbolItem*> lstSmbItem;
        const symbolItem* it;
        int count = 0;
        for (it=this; it && count < MAXSCOPE; it = it->m_scope.get(), count++)
            lstSmbItem.push_back(it);
        if (count >= MAXSCOPE)
            //throw exception("Internal error");
            throw exception();

        boost::wave::token_id prevTk=T_FIRST_TOKEN;
        std::string aux = "::";
        for (bool goOut=false; !goOut&&lstSmbItem.size()&&
            (*lstSmbItem.back()).get_value().size(); 
            lstSmbItem.pop_back()) {
            it=lstSmbItem.back();
			if (it->get_symbol_type() == symbolItem::point_to_function) {
				aux = "";
			}
            scp += aux + it->get_value().c_str();
            token_t tkaux = *it;
            switch(*it) {
                case T_CHAR:
                case T_WCHART:
                case T_BOOL:
                case T_SHORT:
                case T_INT:
                case T_LONG:
                case T_SIGNED:
                case T_UNSIGNED:
                case T_FLOAT:
                case T_DOUBLE:
                case T_VOID:
                    scp = it->get_value().c_str();
                    goOut=true;
                    break;
                case T_IDENTIFIER:
                    switch(it->get_identifier_type()) {
                        case T_CLASS_NAME:
                        case T_ENUM_NAME:
                        case T_TEMPLATE_NAME:
                             aux = "::";
                             break;
                        case T_ORIGINAL_NAMESPACE_NAME:
                            if (    static_cast<symbolItem::identifierType>(prevTk) == T_CLASS_NAME || static_cast<symbolItem::identifierType>(prevTk) == T_ENUM_NAME
                                 || static_cast<symbolItem::identifierType>(prevTk) == T_TEMPLATE_NAME)
                                 scp = std::string("::") + it->get_value().c_str();
                            aux = "::";
                            break;
                        default:
                            aux = "$";
                            break;
                    }
                    break;
                default:
                    aux = "$";
                    break;
            }
            prevTk = *it;
        }
    }
    delete[] m_str; // Free previous value
    m_str = new char[scp.size()+1];
    strcpy(m_str, scp.c_str());
}

symbolItem& symbolItem::operator=(const symbolItem& s) {
    //*static_cast<token_t*>(this)=*static_cast<const token_t*>(&s);
	m_definitions = s.m_definitions;
	m_declarations = s.m_declarations;
	m_references = s.m_references;
    m_typeTk=s.m_typeTk;
    m_sblTyp=s.m_sblTyp;
    if (s.m_scope.get() == this)
        //throw exception("Internal error");
        throw exception();
    m_scope=s.m_scope;
    m_stt=s.m_stt;
    delete[] m_str; // Free previous value
    m_str = new char[(s.m_str?strlen(s.m_str):0)+1];
    strcpy(m_str, s.m_str?s.m_str:"");
    m_adorners = s.m_adorners;
    m_inners = s.m_inners;
    m_inrsCreated = s.m_inrsCreated;
    m_paramPos = s.m_paramPos;
    m_identifierType = s.m_identifierType;

    return *this;
}

symbolItemPtr symbolItem::add(symbolItemPtr pinr) {
    m_inners.push_back(pinr);
    
    return pinr;
}

const symbolItemPtr symbolItem::add(const symbolItem& inr) {
    symbolItemPtr l_pinr = symbolItemPtr(new symbolItem(inr));
    m_inrsCreated.push_back(l_pinr);  // TODO: study the functionality of m_inrsCreated. ALB 27apr06
    
    return add(l_pinr);
}

symbolItem const smb_FIRST_TOKEN(T_FIRST_TOKEN, 0);
}

#if defined(_MSC_VER) && (_MSC_VER >= 1400)
#pragma warning ( default : 4996 )
#pragma warning ( default : 4800 )
#pragma warning ( default : 4355 )
#endif
